<?php

declare(strict_types=1);

namespace Zlf\AppValidate\Rule;

/**
 * 字符串验证器
 */
class StringValidate extends RuleAbstract
{
    /**
     * 最大长度限制
     * @var int
     */
    protected $_max = 0;

    /**
     * 超过最大长度时的错误信息
     * @var string
     */
    protected $_maxError = '{label}最多不能超过{max}个字';

    /**
     * 最小长度限制
     * @var int
     */
    protected $_min = 0;

    /**
     * 低于最小长度时的错误信息
     * @var string
     */
    protected $_minError = '{label}不能少于{min}个字';

    /**
     * 默认错误消息
     * @var string
     */
    protected $_error = '{label}不是有效的string类型数据';

    /**
     * 设置字符串最大长度
     *
     * @param int $max 最大长度
     * @return $this 当前实例
     */
    public function setMax(int $max): StringValidate
    {
        $this->_max = $max;
        return $this;
    }

    /**
     * 设置超出最大长度时的自定义错误信息
     *
     * @param string $_maxError 自定义错误信息
     * @return $this 当前实例
     */
    public function setMaxError(string $_maxError): StringValidate
    {
        $this->_maxError = $_maxError;
        return $this;
    }

    /**
     * 设置字符串最小长度
     *
     * @param int $min 最小长度
     * @return $this 当前实例
     */
    public function setMin(int $min): StringValidate
    {
        $this->_min = $min;
        return $this;
    }

    /**
     * 设置低于最小长度时的自定义错误信息
     *
     * @param string $_minError 自定义错误信息
     * @return $this 当前实例
     */
    public function setMinError(string $_minError): StringValidate
    {
        $this->_minError = $_minError;
        return $this;
    }

    /**
     * 验证逻辑实现
     *
     * @param mixed $value 待验证的值
     * @param string $label 字段标签，用于替换错误信息中的占位符
     * @return bool 验证是否通过
     */
    public function validate($value, string $label = ''): bool
    {
        // 检查输入是否为字符串类型
        if (!is_string($value)) {
            return $this->addError($this->_error, $label);
        }

        // 如果允许跳过空值且值为空，则直接通过验证
        if (empty($value) && $this->_noSkipping === true) {
            $this->_value = $value;
            return true;
        }

        // 获取字符串长度
        $strLen = mb_strlen($value);

        // 检查是否低于设定的最小长度
        if ($this->_min > 0 && $strLen < $this->_min) {
            $this->addError(str_replace(['{label}', '{min}'], [$label, strval($this->_min)], $this->_minError), $label);
        }

        // 检查是否超出设定的最大长度
        if ($this->_max > 0 && $strLen > $this->_max) {
            $this->addError(str_replace(['{label}', '{max}'], [$label, strval($this->_max)], $this->_maxError), $label);
        }

        // 如果有任何失败的检查，则返回false
        if ($this->isFail()) {
            return false;
        }

        // 验证通过，设置值并返回true
        $this->_value = $value;
        return true;
    }
}